package com.bms.cfcmms.service.authority;

import com.bms.cfcmms.util.Constants;
import com.bms.cfcmms.util.SpringUtils;
import com.bms.cfcmms.model.system.authority.Token;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Created by carl on 2017/3/20.
 */
@Service
public class RedisTokenService {

    private RedisTemplate redis;

    @Autowired
    public void setRedis(RedisTemplate redis) {
        this.redis = redis;
        //泛型设置成Long后必须更改对应的序列化方案
        redis.setKeySerializer(new JdkSerializationRedisSerializer());
    }

    public Token createToken() {

        //使用uuid作为源token
        String userId = UUID.randomUUID().toString().replace("-", "");

        Token token = createJwt(userId, Constants.TOKEN_EXPIRES_HOUR * 3600 * 1000);
        //存储到redis并设置过期时间
        redis.boundValueOps(userId).set(token, Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
        return token;
    }

    public String checkToken(String userId) {
        if (!SpringUtils.hasLength(userId)) {
            return null;
        }
        Token tokenModel = (Token) redis.boundValueOps(userId).get();
        Claims claims = parseJwt(tokenModel.getToken());
        String userName = claims.getSubject();
        if (!SpringUtils.hasLength(userName)) {
            return null;
        }
        //如果验证成功，说明此用户进行了一次有效操作，延长token的过期时间
        redis.boundValueOps(userId).expire(Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
        return userName;
    }

    public void deleteToken(String userId) {
        redis.delete(userId);
    }

    /**
     * 由字符串生成加密key
     * @return
     */
    private SecretKey generalKey(){
        String stringKey = "7786df7fc3a34e26a61c034d5ec8245d";
        byte[] encodedKey = Base64.decodeBase64(stringKey);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    private Token createJwt(String loginName, long ttlMillis){

        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date( nowMillis);
        SecretKey key = generalKey();
        JwtBuilder builder = Jwts.builder()
                .setId(loginName)
                .setIssuedAt(now)
                .setSubject(loginName)
                .signWith(signatureAlgorithm, key);
        if (ttlMillis >= 0){
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date( expMillis);
            builder.setExpiration( exp);
        }
        return new Token(loginName, builder.compact());
    }

    /**
     * 解密 token,
     * @param token
     * @return 解密后的内容,可用claims.get方法提取出数据
     * @throws Exception
     *
     */
    private Claims parseJwt(String token){
        SecretKey key = generalKey();
        Claims claims = Jwts.parser()
                .setSigningKey( key)
                .parseClaimsJws(token).getBody();
        return claims;
    }
}
